import { ref, computed } from 'vue';
import type { Ref } from 'vue';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';

/**
 * 自动将选择日期范围数组生成相应字段，用于Element-Plus日期范围选择
 *
 * @export
 * @param {Ref<any>} obj 包含开始日期和结束日期的对象
 * @param {string} [startKey='start_time'] 开始日期key
 * @param {string} [endKey='end_time'] 结束日期key
 * @return {*} 包含开始日期和结束日期的数组
 */
export function useDatetime(
  obj: Ref<any>,
  startKey = 'start_time',
  endKey = 'end_time'
) {
  const datetime = computed<[string, string]>({
    set: function (val) {
      obj.value[startKey] = val?.[0] ?? '';
      obj.value[endKey] = val?.[1] ?? '';
    },
    get: function () {
      if (import.meta.env.MODE === 'development') {
        // 只有开发环境才会提示
        if (!Object.hasOwn(obj.value, startKey)) {
          console.warn(
            `useDatetime提示：obj.value中不存在您提供的startKey属性，obj.value:`,
            obj.value,
            'startKey：',
            startKey
          );
        }
        if (!Object.hasOwn(obj.value, endKey)) {
          console.warn(
            `useDatetime提示：obj.value中不存在您提供的endKey属性，obj.value:`,
            obj.value,
            'startKey：',
            endKey
          );
        }
      }

      return [obj.value[startKey], obj.value[endKey]];
    },
  });
  return datetime;
}

/**
 * 生成默认时间，用于Element-Plus日期范围选择时默认时间设置
 *
 * @export
 * @param {string} [startTime='00:00:00'] 开始时间，格式必须是HH:mm:ss
 * @param {string} [endTime='23:59:59'] 结束时间，格式必须是HH:mm:ss
 * @return {Ref<[Date, Date]>} 默认时间[开始时间，结束时间]
 */
export function useDefaultTime(startTime = '00:00:00', endTime = '23:59:59') {
  const defaultTime = ref<[Date, Date]>([
    new Date(`2000-01-01 ${startTime}`),
    new Date(`2000-01-01 ${endTime}`),
  ]);
  return defaultTime;
}

/**
 * Element-Plus 日期选择配置项
 * @returns
 */
export function useDatetimePicker() {
  /**
   * 生成快捷选项
   * @param {boolean} [isTimestamp = false] 当前date-picker的value-format是否为时间戳timestamp格式
   * @param {{text:string,value:number[]}[]} shortcutArr 快捷选择，数据格式[{ text: "今天", value: [0, 0] }]，有默认值
   * @returns 快捷选项
   */
  function createShortcuts(
    shortcutArr: { text: string; value: [number, number] }[] = [
      { text: '今天', value: [0, 0] },
      { text: '昨天', value: [1, 1] },
      { text: '近7天', value: [0, 6] },
      { text: '近30天', value: [0, 29] },
    ]
  ) {
    const shortcuts = shortcutArr.map((item) => {
      return {
        text: item.text,
        value: () => {
          const start = dayjs()
            .subtract(item.value[1], 'day')
            .startOf('day')
            .toDate();
          const end = dayjs()
            .subtract(item.value[0], 'day')
            .endOf('day')
            .toDate();

          return [start, end];
        },
      };
    });
    return shortcuts;
  }

  /**
   * 生成禁用日期函数
   *
   * @param {(string | Date)} minDate 最小日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或者日期
   * @param {(string | Date)} maxDate 最大日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或着日期
   * @param {({ minDate: Date | null; maxDate: Date | null })} [pickDate={minDate: null, maxDate: null}] 实时选择的日期
   * @param {number} [rangeDays=0] 可选日期范围天数，0代表不限制范围天数，比如最大可选择30天传30即可；使用此参数时，必须同时使用calendarChange函数，否则无效。
   * @return {*} 用户element-plus的禁用日期函数
   */
  function createBaseDisabledDate(
    minDate: string | Date,
    maxDate: string | Date,
    pickDate: { minDate: Date | null; maxDate: Date | null } = {
      minDate: null,
      maxDate: null,
    },
    rangeDays = 0
  ) {
    function disabledDate(time: Date) {
      const minDateNum = (
        minDate instanceof Date ? minDate : Date.parse(minDate)
      )
        ? dayjs(minDate).startOf('day').valueOf()
        : 0;
      const maxDateNum = (
        maxDate instanceof Date ? maxDate : Date.parse(maxDate)
      )
        ? dayjs(maxDate).endOf('day').valueOf()
        : 0;
      if (rangeDays > 0 && pickDate.minDate) {
        const rangeMinDateNum =
          rangeDays > 0
            ? dayjs(pickDate.minDate)
                .subtract(rangeDays, 'day')
                .startOf('day')
                .valueOf()
            : 0;
        const rangeMaxDateNum =
          rangeDays > 0
            ? dayjs(pickDate.minDate)
                .add(rangeDays - 1, 'day')
                .endOf('day')
                .valueOf()
            : 0;
        // minDateNum === 0 说明minDateNum未设置，则直接使用rangeMinDateNum,
        // 否则如果当前选择日期-范围天数比设置的最小日期还要小，那么最小日期就是设置的最小日期
        const min =
          minDateNum === 0
            ? rangeMinDateNum
            : rangeMinDateNum <= minDateNum
            ? minDateNum
            : rangeMinDateNum;

        // maxDateNum === 0 说明maxDateNum未设置，则直接使用rangeMaxDateNum,
        // 否则如果当前选择日期+范围天数比设置的最大日期还要大，那么最大日期就是设置的最大日期
        const max =
          maxDateNum === 0
            ? rangeMaxDateNum
            : rangeMaxDateNum >= maxDateNum
            ? maxDateNum
            : rangeMaxDateNum;
        return time.getTime() > max || time.getTime() <= min;
      } else if (minDateNum && maxDateNum) {
        return time.getTime() > maxDateNum || time.getTime() < minDateNum;
      } else if (minDateNum) {
        return time.getTime() < minDateNum;
      } else if (maxDateNum) {
        return time.getTime() >= maxDateNum;
      } else {
        return false;
      }
    }
    return disabledDate;
  }

  /**
   * 生成禁用日期
   *
   * @param {(string | Date)} minDate 最小日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或者日期
   * @param {(string | Date)} [maxDate=new Date()] 最大日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或着日期
   * @return {*}
   */
  function createDisabledDate(
    minDate: string | Date,
    maxDate: string | Date = new Date()
  ) {
    const disabledDate = createBaseDisabledDate(minDate, maxDate);
    return disabledDate;
  }

  /**
   * 根据当前选择禁用日期
   *
   * @param {number} rangeDays 可选日期范围天数，比如最大可选择30天传30即可
   * @param {string} minDate 最小日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或者日期
   * @param {string} maxDate 最大日期 可以转换为日期的字符串，数据格式 YYYY-MM-dd，或者日期
   * @return {*} 用于在日期选择组件上v-bind的disabledDate和v-on的calendarChange
   */
  function createRealSelectDisableDate(
    rangeDays: number,
    minDate: string | Date = '',
    maxDate: string | Date = ''
  ) {
    // 选择日期
    const pickDate: { minDate: Date | null; maxDate: Date | null } = {
      minDate: null,
      maxDate: null,
    };

    const disabledDate = createBaseDisabledDate(
      minDate,
      maxDate,
      pickDate,
      rangeDays
    );
    /**
     * 选中日期后会执行的回调
     * @param {[Date,Date]} date 选中日期后会执行的回调，只有当 daterange 或 datetimerange 才生效
     */
    function calendarChange(date: [Date, Date]) {
      const [minDate, maxDate] = date;
      if (maxDate) {
        pickDate.minDate = null;
      } else {
        pickDate.minDate = minDate;
      }
    }

    return { disabledDate, calendarChange };
  }

  return {
    createShortcuts,
    createDisabledDate,
    createRealSelectDisableDate,
  };
}
